<?php
class RegistrationPage extends MemberPage {
	private static $default_parent = 'MemberPackagePage';
	
    private static $db = array();

    private static $has_one = array();

}

class RegistrationPage_Controller extends MemberPage_Controller {

    /**
     * An array of actions that can be accessed via a request. Each array element
     * should be an action name, and the
     * permissions or conditions required to allow the user to access it.
     *
     * <code>
     * array (
     *     'action', // anyone can access this action
     *     'action' => true, // same as above
     *     'action' => 'ADMIN', // you must have ADMIN permissions to access this
     * action
     *     'action' => '->checkAction' // you can only access this action if
     * $this->checkAction() returns true
     * );
     * </code>
     *
     * @var array
     */
    private static $allowed_actions = array (
        'PackageForm',
        'signup',
        'SignupForm',
        'confirm',
        'ConfirmForm',
        'complete'
    );

    public function index(){
    	$confirm_msg = _t('RegistrationPage.CONFIRM_MSG', 'Are you sure you want to purchase package');
		$error_msg = _t('RegistrationPage.AGREE_REQUIRED', 'Please check the Purchase Terms and Condition boxes below to acknowledge your acceptance, agreement and understanding of the terms and agreements.');
		$js = <<<JS
			(function($) {
				$('.buy').on('click', function(e) {
					e.preventDefault();
					if($('#PrivateInvestmentAgreement').prop('checked') == false){
						alert('$error_msg');
						return false;
					}
					var tr = $(this).parents('tr');
					var confirm_msg = '$confirm_msg ' + tr.find('.package').text() + ' ' + tr.find('.price').find('select.dropdown option:selected').text() + '?';
  					if (confirm(confirm_msg)){
  						window.location.href = $(this).data('link') + '/' + tr.find('.price').find('select.dropdown').val();
         				return true;
      				}
      				return false;
				});
			})(jQuery);
JS;
		Requirements::customScript($js, 'RegisterPackage');
		
        return array('Form' => $this->PackageForm());
    }
	
	public function PackageForm(){
		$content = '<div class="table-responsive"><table class="table table-striped table-hover">';
		$content .= sprintf('<thead><tr><th>%s</th><th class="text-right" width="200px">%s</th><th></th></tr></thead>', _t('RegistrationPage.PACKAGE', 'Package'), _t('RegistrationPage.PRICE', 'Price'));
		$content .= '<tbody>';
		$packages = Package::get()->filter('Type', 'Register')->filter('IsActive', 1);
		$groups = $this->CurrentMember()->Groups()->getIDList();
		foreach($packages as $package){
			if($package->RestrictGroups()->byIDs($groups)->count()){
				continue;
			}
			
			$price_list = array();
			foreach($package->Prices() as $price){
				$price_list[$price->ID] = $price->dbObject('Price')->Nice();
			}
			if(!sizeof($price_list)) continue;
			$price_field = DropdownField::create(sprintf('Price%s', $package->ID), '', $price_list)->setAttribute('style', 'width: 200px !important')->forTemplate();
			$content .= sprintf('<tr><td class="package">%s</td><td class="text-right price" width="200px">%s</td><td class="text-right"><a href="javascript: void(0);" data-link="%s" class="btn btn-primary buy">%s</a></td></tr>', $package->Title, $price_field, Controller::join_links($this->Link('signup'), $package->ID), _t('RegistrationPage.BUY', 'Buy'));
		}
		$content .= '</tbody>';
		$content .= '</table></div>';
		
		$check_box = sprintf(
			'<p class="bg-danger">%s</p><p class="bg-danger">%s</p><div class="checkbox"><label><input type="checkbox" name="PrivateInvestmentAgreement" value="1" id="PrivateInvestmentAgreement">%s <!--a href="%s" target="_blank">%s</a--></label></div>', 
			_t('RegistrationPage.TERM_NOTE', 'Below is the contractural terms and agreements that you are bound by as a client of BJ City for signing up the package above. We recommend that you take the time to read each of them carefully.'), 
			_t('RegistrationPage.AGREE_NOTE', 'Please check the boxes below to acknowledge your acceptance, agreement and understanding of the terms and agreements.'), 
			_t('RegistrationPage.PRIVATE_INVESTMENT_AGREEMENT', 'Purchase Terms and Condition'),
			'site/images/terms.pdf',
			_t('RegistrationPage.BUTTONDOWNLOADPDF', 'Download PDF')
		);

		$fields = FieldList::create(
			LiteralField::create('Package', $content),
			LiteralField::create('AgreeTerm', $check_box)
		);
		
		$actions = FieldList::create();
		
		return Form::create($this, 'PackageForm', $fields, $actions);
	}
	
	public function signup(){
		return array('Form' => $this->SignupForm());
	}
    
    public function SignupForm(){
    	$package_title = _t('RegistrationPage.UNKNOWN_PACKAGE', "Unknown member package");
		$package = Package::get()->filter('Type', 'Register')->filter('IsActive', 1)->byID((int)$this->request->param('ID'));
		if($package && !$package->RestrictGroups()->byIDs($this->CurrentMember()->Groups()->getIDList())->count()){
			if($price = $package->Prices()->byID((int)$this->request->param('OtherID'))){
				$package_title = sprintf('%s - %s', $package->Title, $price->dbObject('Price')->Nice());
			}
		}
        $personal_fields = CompositeField::create(Member::create()->getRegisterFields())->addExtraClass('personal');
        if(Session::get('SponsorUsername') && Distributor::get_id_by_username(Session::get('SponsorUsername'))){
            $fields = FieldList::create(
            	HiddenField::create('PackageID', 'PackageID', $this->request->param('ID')),
            	HiddenField::create('PriceID', 'PriceID', $this->request->param('OtherID')),
            	HtmlEditorField_Readonly::create('Package', _t('RegistrationPage.PACKAGE', 'Package'), $package_title),
                SponsorField::create('Sponsor', _t('RegistrationPage.SPONSOR_USERNAME', 'Sponsor Username'), Session::get('SponsorUsername')),
                PlacementField::create('Placement', _t('RegistrationPage.PLACEMENT_USERNAME', 'Placement Username'), Session::get('PlacementUsername'), Session::get('PlacementPosition') ? Session::get('PlacementPosition') : '')
            );
        }
        else{
            $fields = FieldList::create(
            	HiddenField::create('PackageID', 'PackageID', $this->request->param('ID')),
            	HiddenField::create('PriceID', 'PriceID', $this->request->param('OtherID')),
            	HtmlEditorField_Readonly::create('Package', _t('RegistrationPage.PACKAGE', 'Package'), $package_title),
                SponsorField::create('Sponsor', _t('RegistrationPage.SPONSOR_USERNAME', 'Sponsor Username')),
                PlacementField::create('Placement', _t('RegistrationPage.PLACEMENT_USERNAME', 'Placement Username'))
            );
        }
		$fields->merge($personal_fields);
		
		$fields->push(HtmlEditorField_Readonly::create('CertifyNote', '', _t('RegistrationPage.CERTIFY_NOTE', 'I hereby attest and certify that the above information is complete and accurate and I agree to be bound by these terms and conditions. I also authorise company to verify any or all of the foregoing information. This electronic signature has the same validity and effect as a signature affixed by hand.')));
		
		$fields->push(TextField::create('CertifyName', _t('RegistrationPage.NAME', 'Name')));
		$fields->push(DateField::create('CertifyDate', _t('RegistrationPage.DATE', 'Date'), date('Y-m-d'))->setConfig('showcalendar', false)->setAttribute('readonly', 'readonly'));
		
		$register_type = array();
		if($this->CurrentMember()->AllowRegisterFree){
			$register_type['Free'] = _t('RegistrationPage.REGISTER_FREE', 'Register without payment and bv but got invest program');
		}

		if($this->CurrentMember()->AllowRegisterWithoutPayment){
			$register_type['WithoutPayment'] = _t('RegistrationPage.REGISTER_WITHOUT_PAYMENT', 'Register without payment but got bv');
		}

		if(sizeof($register_type)){
			$fields->insertBefore(DropdownField::create('RegisterType', _t('RegistrationPage.REGISTER_TYPE', 'Register Type'))->setSource($register_type), 'Package');
		}
		else{
			$fields->push(HiddenField::create('RegisterType', _t('RegistrationPage.REGISTER_TYPE', 'Register Type'), 'Normal'));
		}

        $actions = FieldList::create(
            FormAction::create('doSignup', _t('RegistrationPage.BUTTONSIGNUP', 'Signup'))
        );
        
        $validators = Registration_Validator::create('PackageID', 'Sponsor', 'Placement', 'Username', 'Email', 'Passport', 'Mobile', 'Name', 'Term', 'CertifyName', 'CertifyDate', 'Agree');
        
        return Form::create($this, 'SignupForm', $fields, $actions, $validators);
    }
    
    public function doSignup($data, $form){
        try {
            $member = Member::create();
            $form->saveInto($member);
            $member->AgreeTermAndCondition = 1;
			$member->Activated = 1;
            $member->IsDistributor = 1;
            $member->IsRegister = 1;
            Session::set('SignupMember', $member);
            return $this->redirect($this->Link('confirm'));
        }
        catch(ValidationException $e) {
            SS_Log::log(new Exception(print_r($e->getMessage(), true)), SS_Log::NOTICE);
            $form->sessionMessage($e->getResult()->message(), 'error');
        }
        return $this->redirectBack();
    }

	public function confirm(){
		if(Session::get('SignupMember')){
			return array('Form' => $this->ConfirmForm()->loadDataFrom(Session::get('SignupMember')));
		}
		
		return $this->redirect($this->Link());
	}
	
	public function ConfirmForm(){
		if(!Session::get('SignupMember')){
			return $this->redirect($this->Link());
		}
		$package_title = _t('RegistrationPage.UNKNOWN_PACKAGE', "Unknown member package");
		$package_price = 0;
		$package = Package::get()->filter('Type', 'Register')->filter('IsActive', 1)->byID((int)Session::get('SignupMember')->PackageID);
		if($package && !$package->RestrictGroups()->byIDs($this->CurrentMember()->Groups()->getIDList())->count()){
			if($price = $package->Prices()->byID((int)Session::get('SignupMember')->PriceID)){
				$package_price = $price->Price;
				$package_title = sprintf('%s - %s', $package->Title, $price->dbObject('Price')->Nice());
			}
		}
		
		if($package_price <= 0){
			return $this->redirect($this->Link());
		}
		
        $personal_fields = Member::create()->getRegisterFields();
        $fields = FieldList::create(
        	HiddenField::create('PackageID', 'PackageID', $this->request->param('ID')),
            HiddenField::create('PriceID', 'PriceID', $this->request->param('OtherID')),
        	HtmlEditorField_Readonly::create('Package', _t('RegistrationPage.PACKAGE', 'Package'), $package_title),
            SponsorField::create('Sponsor', _t('RegistrationPage.SPONSOR_USERNAME', 'Sponsor Username')),
            PlacementField::create('Placement', _t('RegistrationPage.PLACEMENT_USERNAME', 'Placement Username'))
        );
		$fields->merge($personal_fields);
		
		$register_type = array();
		if($this->CurrentMember()->AllowRegisterFree){
			$register_type['Free'] = _t('RegistrationPage.REGISTER_FREE', 'Register without payment and bv but got invest program');
		}

		if($this->CurrentMember()->AllowRegisterWithoutPayment){
			$register_type['WithoutPayment'] = _t('RegistrationPage.REGISTER_WITHOUT_PAYMENT', 'Register without payment but got bv');
		}

		if(sizeof($register_type)){
			$fields->insertBefore(DropdownField::create('RegisterType', _t('RegistrationPage.REGISTER_TYPE', 'Register Type'))->setSource($register_type), 'Package');
		}
		else{
			$fields->push(HiddenField::create('RegisterType', _t('RegistrationPage.REGISTER_TYPE', 'Register Type'), 'Normal'));
		}
		
		foreach($fields as $field){
			if($field->class == 'LiteralField'){
				continue;
			}
			
			$field = $field->performReadonlyTransformation();
			if($field->hasMethod('setIncludeHiddenField')){
				$field->setIncludeHiddenField(true);
			}
			$fields->push($field);
		}
		
		if(Session::get('SignupMember')->RegisterType == 'WithoutPayment' || Session::get('SignupMember')->RegisterType == 'Free'){
			$validators = Registration_Validator::create('PackageID', 'Sponsor', 'Placement', 'Username', 'Email', 'Passport', 'Mobile', 'Name');
        }
		else{
			$supported_methods = Payment::get_supported_methods();
	        if(sizeof($supported_methods)){
	            foreach($supported_methods as $method => $title){
	                if($method != 'PurchasePlusCashPayment'){
	                    Payment::remove_supported_methods($method);
	                }
	            }
	        }
	
	        $fields = Payment::combined_form_fields($fields, $this->CurrentMember()->ID, $package_price);
	        
	        $validators = RegistrationPayment_Validator::create('PackageID', 'Sponsor', 'Placement', 'Username', 'Email', 'Passport', 'Mobile', 'Name');
		}
		
		$actions = FieldList::create(
            FormAction::create('doConfirm', _t('RegistrationPage.CONFIRM_SIGNUP', 'Confirm Signup'))
        );
        
        return Form::create($this, 'ConfirmForm', $fields, $actions, $validators);
    }
	
	public function doConfirm($data, $form){
        try {
            DB::getConn()->transactionStart();
            $member = Session::get('SignupMember');
            $member->write();
			
			$package = Package::get()->byID(Session::get('SignupMember')->PackageID);
			$price = $package->Prices()->byID(Session::get('SignupMember')->PriceID);
			
			if($member->RegisterType == 'WithoutPayment'){
				$billing_address = PackageBillingAddress::create()
				->setField('Name', $this->CurrentMember()->getName())
				->setField('Contact', $this->CurrentMember()->Mobile)
				->setField('Email', $this->CurrentMember()->Email)
				->setField('Address', $this->CurrentMember()->Address)
				->setField('Suburb', $this->CurrentMember()->Suburb)
				->setField('State', $this->CurrentMember()->State)
				->setField('Postcode', $this->CurrentMember()->Postcode)
				->setField('Country', $this->CurrentMember()->Country);
				$billing_address->write();
				
				$order = OrderPackage::create()
				->setField('Type', $package->Type)
				->setField('Title', $package->Title)
				->setField('Price', $price->Price)
				->setField('BV', $price->BV)
				->setField('PackageID', $package->ID)
				->setField('UpgradeGroupID', $package->UpgradeGroupID)
				->setField('BillingAddressID', $billing_address->ID)
				->setField('MemberID', $member->ID)
				->setField('PaidByID', $this->CurrentMember()->ID)
				->setField('SoldByID', $member->Sponsor()->ID);
				$order->write();
				
				OrderPackage::update_status($order->ID, 'Fully Paid');
			}
			else if($member->RegisterType == 'Free'){
				if($package->UpgradeGroupID) {
	                $member->Groups()->add($package->UpgradeGroupID);
					$member->setField('MaxPayout', $price->Price * 3)->write();
				}
				
				$setting_table = Config::inst()->get('InvestProgram', 'setting_table');
				$current_setting = $setting_table[$package->UpgradeGroup()->Code];
				$next_payout = date("Y-m-d", strtotime("+1 day", time()));
				$dw = date("w", strtotime($next_payout));
				if($dw == 0){
					$next_payout = strtotime("+1 day", strtotime($next_payout));
				}
				else if($dw == 6){
					$next_payout = strtotime("+2 day", strtotime($next_payout));
				}
				$id = InvestProgram::create()
				->setField('Percentage', $current_setting['percentage'])
				->setField('MaxDay', $current_setting['max_day'])
				->setField('NextPayout', $next_payout)
				->setField('MemberID', $member->ID)
				->setField('GroupID', $package->UpgradeGroupID)
				->write();
			} 
			else {
				$receipt = Receipt::create()
				->setField('TotalAmount', $data['TotalAmount'])
				->setField('Currency', SiteCurrencyConfig::current_site_currency())
				->setField('MemberID', $this->CurrentMember()->ID)
				->updateTransactionType('REGISTER');
				$receipt->write();
				$payment = $receipt->addPayment($data['Payment'], $data);
				
				$billing_address = PackageBillingAddress::create()
				->setField('Name', $this->CurrentMember()->getName())
				->setField('Contact', $this->CurrentMember()->Mobile)
				->setField('Email', $this->CurrentMember()->Email)
				->setField('Address', $this->CurrentMember()->Address)
				->setField('Suburb', $this->CurrentMember()->Suburb)
				->setField('State', $this->CurrentMember()->State)
				->setField('Postcode', $this->CurrentMember()->Postcode)
				->setField('Country', $this->CurrentMember()->Country);
				$billing_address->write();
				
				$order = OrderPackage::create()
				->setField('Type', $package->Type)
				->setField('Title', $package->Title)
				->setField('Price', $price->Price)
				->setField('BV', $price->BV)
				->setField('PackageID', $package->ID)
				->setField('UpgradeGroupID', $package->UpgradeGroupID)
				->setField('BillingAddressID', $billing_address->ID)
				->setField('PaymentReceiptID', $receipt->ID)
				->setField('MemberID', $member->ID)
				->setField('PaidByID', $this->CurrentMember()->ID)
				->setField('SoldByID', $member->Sponsor()->ID);
				$order->write();
			}
			
			Session::clear('SignupMember');
			Session::clear('SponsorUsername');
			Session::clear('PlacementUsername');
			Session::clear('PlacementPosition');
            Session::set('Registered', Member::get()->byID($member->ID));
            DB::getConn()->transactionEnd();
			
			if($member->RegisterType == 'Free' || $member->RegisterType == 'WithoutPayment'){
				return $this->redirect($this->Link('complete'));
			}
			else{
				return $this->redirect($payment->ProcessLink());
			}
        }
        catch(ValidationException $e) {
            DB::getConn()->transactionRollback();
            SS_Log::log(new Exception(print_r($e->getMessage(), true)), SS_Log::NOTICE);
            $form->sessionMessage($e->getResult()->message(), 'error');
        }
        return $this->redirectBack();
    }
    
    public function complete(){
        if(Session::get('Registered')){
            $member = Session::get('Registered');
            Session::clear('Registered');
            return array(
                'Member' => $member
            );
        }
        
        return $this->redirect($this->Link());
    }
}

class Registration_Validator extends RequiredFields {

    protected $customRequired = array();

    /**
     * Constructor
     */
    public function __construct() {
        $required = func_get_args();
        if(isset($required[0]) && is_array($required[0])) {
            $required = $required[0];
        }
        $required = array_merge($required, $this->customRequired);

        parent::__construct($required);
    }

    /**
     * Check if the submitted list data is valid (server-side)
     *
     * @param array $data Submitted data
     * @return bool Returns TRUE if the submitted data is valid, otherwise
     *              FALSE.
     */
    function php($data) {
        $valid = parent::php($data);

		$sponsor_id = $data['Sponsor'] ? Distributor::get_id_by_username($data['Sponsor']) : 0;
        if($sponsor_id){
        	$obj = Placement::get()->find('MemberID', $sponsor_id);
			$placement_id = $data['Placement']['username'] ? Distributor::get_id_by_username($data['Placement']['username']) : 0;
			$placement_position = 0;
			if($data['Placement']['position'] == 'Manual Left'){
				$placement_position = 1;
			} else if($data['Placement']['position'] == 'Manual Right'){
				$placement_position = 2;
			}
        	$checkPlacement = Placement::get()
        	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
        	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
			->filter('MemberID', (int)$placement_id)->count();

			if(!$checkPlacement){
				$this->validationError('Placement', _t('RegistrationPage.PLACEMENT_USERNAME_INVALID', "The placement username is invalid"));
            	$valid = false;
			} else if($placement_position) {
				$obj = Placement::get()->find('MemberID', $placement_id);
				$checkPosition = Placement::get()
	        	->filter('ParentID', (int)$placement_id)
	        	->filter('NSeqno', (int)$placement_position)->count();
	
				if($checkPosition){
					$this->validationError('Position', _t('RegistrationPage.POSITION_EXISTS', "The placement position is already registered by other member"));
	            	$valid = false;
				}
			}
        } else {
        	$this->validationError('Sponsor', _t('RegistrationPage.SPONSOR_USERNAME_INVALID', "The sponsor username is invalid"));
			$valid = false;
        }
		
		$current_member = Controller::curr()->CurrentMember();
		$package = Package::get()->filter('Type', 'Register')->filter('IsActive', 1)->byID((int)$data['PackageID']);
		if(!$package || $package->RestrictGroups()->byIDs($current_member->Groups()->getIDList())->count()){
			$this->validationError('Package', _t('RegistrationPage.PACKAGE_INVALID', "Member package is invalid"));
			$valid = false;
		} else if(!$package->Prices()->byID((int)$data['PriceID'])){
			$this->validationError('Package', _t('RegistrationPage.PACKAGE_PRICE_INVALID', "Member package price is invalid"));
			$valid = false;
		}

        // Execute the validators on the extensions
        if($this->extension_instances) {
            foreach($this->extension_instances as $extension) {
                if(method_exists($extension, 'hasMethod') && $extension->hasMethod('updatePHP')) {
                    $valid &= $extension->updatePHP($data, $this->form);
                }
            }
        }

        return $valid;
    }
}

class RegistrationPayment_Validator extends Payment_Validator {

    protected $customRequired = array();

    /**
     * Constructor
     */
    public function __construct() {
        $required = func_get_args();
        if(isset($required[0]) && is_array($required[0])) {
            $required = $required[0];
        }
        $required = array_merge($required, $this->customRequired);

        parent::__construct($required);
    }

    /**
     * Check if the submitted list data is valid (server-side)
     *
     * @param array $data Submitted data
     * @return bool Returns TRUE if the submitted data is valid, otherwise
     *              FALSE.
     */
    function php($data) {
        $valid = parent::php($data);

		$sponsor_id = $data['Sponsor'] ? Distributor::get_id_by_username($data['Sponsor']) : 0;
        if($sponsor_id){
        	$obj = Placement::get()->find('MemberID', $sponsor_id);
			$placement_id = $data['Placement']['username'] ? Distributor::get_id_by_username($data['Placement']['username']) : 0;
			$placement_position = 0;
			if($data['Placement']['position'] == 'Manual Left'){
				$placement_position = 1;
			} else if($data['Placement']['position'] == 'Manual Right'){
				$placement_position = 2;
			}
        	$checkPlacement = Placement::get()
        	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
        	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
			->filter('MemberID', (int)$placement_id)->count();

			if(!$checkPlacement){
				$this->validationError('Placement', _t('RegistrationPage.PLACEMENT_USERNAME_INVALID', "The placement username is invalid"));
            	$valid = false;
			} else if($placement_position) {
				$obj = Placement::get()->find('MemberID', $placement_id);
				$checkPosition = Placement::get()
	        	->filter('ParentID', (int)$placement_id)
	        	->filter('NSeqno', (int)$placement_position)->count();
	
				if($checkPosition){
					$this->validationError('Position', _t('RegistrationPage.POSITION_EXISTS', "The placement position is already registered by other member"));
	            	$valid = false;
				}
			}
        } else {
        	$this->validationError('Sponsor', _t('RegistrationPage.SPONSOR_USERNAME_INVALID', "The sponsor username is invalid"));
			$valid = false;
        }
		
		$current_member = Controller::curr()->CurrentMember();
		$package = Package::get()->filter('Type', 'Register')->filter('IsActive', 1)->byID((int)$data['PackageID']);
		if(!$package || $package->RestrictGroups()->byIDs($current_member->Groups()->getIDList())->count()){
			$this->validationError('Package', _t('RegistrationPage.PACKAGE_INVALID', "Member package is invalid"));
			$valid = false;
		} else {
			if(!$package->Prices()->byID((int)$data['PriceID'])){
				$this->validationError('Package', _t('RegistrationPage.PACKAGE_PRICE_INVALID', "Member package price is invalid"));
				$valid = false;
			}
		}

        // Execute the validators on the extensions
        if($this->extension_instances) {
            foreach($this->extension_instances as $extension) {
                if(method_exists($extension, 'hasMethod') && $extension->hasMethod('updatePHP')) {
                    $valid &= $extension->updatePHP($data, $this->form);
                }
            }
        }

        return $valid;
    }
}